﻿using System;
using System.Collections.Generic;
using System.Text;

namespace System.Net
{
    /// <summary>
    /// Udp 接收器
    /// </summary>
    public class UdpReceiver
    {
        private System.Net.Sockets.Socket receiveSocket;

        private System.Net.IPEndPoint localEndPoint;

        private byte[] receivebuffer;

        private System.Net.Sockets.SocketAsyncEventArgs receiveSocketArgs;

        public delegate void BinaryInputHandler(byte[] data, System.Net.Sockets.SocketAsyncEventArgs socketAsync);

        private bool enable = false;
        /// <summary>
        /// 获取Udp 接收器是否可用
        /// </summary>
        public bool Enable
        {
            get { return enable && this.receiveSocket != null && this.receiveSocketArgs != null; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="port"></param>
        /// <param name="bufferSize"></param>
        public UdpReceiver(int port, int bufferSize = 10240)
        {
            //  初始化本地网络端点
            this.localEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Any, port);
            //  设置数据接收缓冲区大小
            this.receivebuffer = new byte[bufferSize];

        }

        /// <summary>
        /// 初始化套接字
        /// </summary>
        void Initialize()
        {
            //  释放资源
            this.Close();
            //  初始化套接字
            this.receiveSocket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
            this.receiveSocket.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, System.Net.Sockets.SocketOptionName.ReuseAddress, 1);
            this.receiveSocket.Bind(this.localEndPoint);
            //  初始化异步套接字操作
            this.receiveSocketArgs = new System.Net.Sockets.SocketAsyncEventArgs();
            this.receiveSocketArgs.RemoteEndPoint = this.localEndPoint;
            this.receiveSocketArgs.Completed += new EventHandler<System.Net.Sockets.SocketAsyncEventArgs>(receiveSocketArgs_Completed);
            this.receiveSocketArgs.SetBuffer(this.receivebuffer, 0, this.receivebuffer.Length);
        }

        /// <summary>
        /// 开始接收数据
        /// </summary>
        public void Start()
        {
            if (this.enable)
                return;

            //  
            this.enable = true;

            //  初始化
            this.Initialize();

            //  开始接收
            this.BeginReceive();
        }

        /// <summary>
        /// 停止接收数据
        /// </summary>
        public void Stop()
        {
            //  
            this.Stop();
            //  
            this.enable = false;
        }

        /// <summary>
        /// 关闭
        /// </summary>
        public void Close()
        {
            //  关闭和释放套接字
            using (this.receiveSocket) { if (this.receiveSocket != null) { this.receiveSocket.Close(); this.receiveSocket = null; } }
            //  释放异步套接字操作对象
            using (this.receiveSocketArgs) { if (this.receiveSocketArgs != null) { this.receiveSocketArgs.Dispose(); this.receiveSocketArgs = null; } }
        }

        /// <summary>
        /// 开始接收
        /// </summary>
        void BeginReceive()
        {
            if (!this.Enable)
                return;

            //  执行异步接收数据
            if (!this.receiveSocket.ReceiveFromAsync(receiveSocketArgs))
            {
                this.processReceived(receiveSocketArgs);
            }
        }

        /// <summary>
        /// 接收处理
        /// </summary>
        /// <param name="e"></param>
        void processReceived(System.Net.Sockets.SocketAsyncEventArgs e)
        {
            //  验证异步套接字结果
            if (e.SocketError == System.Net.Sockets.SocketError.Success && e.BytesTransferred > 0)
            {
                //  定义字节数组，用于存储临时数据
                byte[] buffer = new byte[e.BytesTransferred];
                //  将接收的数据拷贝到数据中
                Array.Copy(e.Buffer, e.Offset, buffer, 0, buffer.Length);

                //  TODO:数据处理
            }
            //  继续接收数据
            this.BeginReceive();
        }

        /// <summary>
        /// 异步套接字操作完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void receiveSocketArgs_Completed(object sender, System.Net.Sockets.SocketAsyncEventArgs e)
        {
            //  判断套接字操作类型
            switch (e.LastOperation)
            {
                case System.Net.Sockets.SocketAsyncOperation.ReceiveFrom:
                    //  进行接收处理
                    this.processReceived(e);
                    break;
                default:
                    //throw new ArgumentException("The last operation completed on the socket was not a receive");
                    break;
            }
        }
    }

    #region SocketAsyncEventArgsPool

    /// <summary>
    /// 
    /// </summary>
    public class SocketAsyncEventArgsPool
    {
        Stack<System.Net.Sockets.SocketAsyncEventArgs> m_pool;

        public SocketAsyncEventArgsPool(int capacity)
        {
            m_pool = new Stack<System.Net.Sockets.SocketAsyncEventArgs>(capacity);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public void Push(System.Net.Sockets.SocketAsyncEventArgs item)
        {
            if (item == null) { throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); }
            lock (m_pool)
            {
                m_pool.Push(item);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public System.Net.Sockets.SocketAsyncEventArgs Pop()
        {
            lock (m_pool)
            {
                return m_pool.Pop();
            }
        }

        /// <summary>
        /// 获取异步套接字操作池数量
        /// </summary>
        public int Count
        {
            get { return m_pool.Count; }
        }
    }

    #endregion

    #region BufferManager

    internal sealed class BufferManager
    {
        private Byte[] buffer;
        private Int32 bufferSize;
        private Int32 numSize;
        private Int32 currentIndex;
        private Stack<Int32> freeIndexPool;

        public BufferManager(Int32 numsize, Int32 buffersize)
        {
            this.numSize = numsize;
            this.bufferSize = buffersize;

        }

        public void Inint()
        {
            buffer = new byte[numSize];
            freeIndexPool = new Stack<int>(numSize / bufferSize);
        }

        internal void FreeBuffer(System.Net.Sockets.SocketAsyncEventArgs args)
        {
            freeIndexPool.Push(args.Offset);
            args.SetBuffer(null, 0, 0);
        }

        internal Boolean SetBuffer(System.Net.Sockets.SocketAsyncEventArgs args)
        {
            if (this.freeIndexPool.Count > 0)
            {
                args.SetBuffer(this.buffer, this.freeIndexPool.Pop(), this.bufferSize);
            }
            else
            {
                if ((this.numSize - this.bufferSize) < this.currentIndex)
                {
                    return false;
                }
                args.SetBuffer(this.buffer, this.currentIndex, this.bufferSize);
                this.currentIndex += this.bufferSize;
            }
            return true;
        }
    }

    #endregion
}
